package cn.edu.sjtu.stap.sootbranchinstr;

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import cn.edu.sjtu.stap.callchainfreq.featurecollection.callsite.IndexAndMappingBuilder;
import cn.edu.sjtu.stap.callchainfreq.featurecollection.callsite.SimpleCallEdge;
import cn.edu.sjtu.stap.callchainfreq.featurecollection.simple.VirtualCallEdgeFinder;

import soot.Unit;
import soot.jimple.InstanceInvokeExpr;
import soot.jimple.InvokeStmt;
import soot.tagkit.Tag;

public class VirtualCallDatabase {
	private static List<SimpleCallEdge> virtualCallEdges;
	static int vc_counter = 0;
	public static List<String> optionMethodSigs = null;
	public static String calleeSigOfVirtualEdge = null;
	
	static{
		VirtualCallEdgeFinder.findVirtualCallEdges();
		virtualCallEdges = VirtualCallEdgeFinder.virtualEdges;
	}
	
	public static boolean isVirtualCallExpression(String callerSig, InvokeStmt is){
		boolean isInSet = false;
		String callerIndex = IndexAndMappingBuilder.methodSig2index.get(callerSig);
		String calleeIndex = 
			IndexAndMappingBuilder.methodSig2index.get(is.getInvokeExpr().getMethod().getSignature());
		Tag lineNumTag = is.getTag("LineNumberTag");
		
		for(SimpleCallEdge ve : virtualCallEdges){
			String subSigOfVE = getSubSigFromSig(
					IndexAndMappingBuilder.index2methodSig.get(ve.getCalleeMethodIndex())	
			);
			
			if(   ve.getCallerMethodIndex().equals(callerIndex)
			   && (lineNumTag != null && ve.getCallerLineNum().equals(lineNumTag.toString()))
			   // TODO: Cheng Zhang, check the correctness of this condition
			   && (subSigOfVE != null && subSigOfVE.equals(getSubSigFromSig(is.getInvokeExpr().getMethod().getSignature())))
			){
				System.err.println("virtual call site:" + ++vc_counter);
				optionMethodSigs = ve.getOptionalMethodSigs();
				calleeSigOfVirtualEdge = IndexAndMappingBuilder.index2methodSig.get(ve.getCalleeMethodIndex());
				isInSet = true;
				break;
			}
		}
		
		return isInSet;
	}
	
	public static String getSubSigFromSig(String sig){
		String subSig = null;
		
		if(sig != null){
			// a method signature in Soot is in the form: <className: subSig>
			int colonIndex = sig.indexOf(":");
			int rightBracketIndex = sig.lastIndexOf(">");
			subSig = sig.substring(colonIndex + 1, rightBracketIndex).trim();
		}
		
		return subSig;
	}
}
